package com.qunar.train.mock.util;

import com.google.common.io.Files;

import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

/**
 * @author: xudong.tai
 * @since: 2018/7/3 Description:
 **/
public class ConfigHandle {

    public static void configMapSet(String filepath, String key, String value) {
        try {
            File file = loadConfigToFile(filepath);
            if (!file.exists()) {
                throw new FileNotFoundException("file not found");
            }
            Map<String, String> oldMap = FileTransToMap(file);
            String addKey = "\n" + key + "=" + value;
            String newValue = key + "=" + value;
            String content = "";
            FileWriter fileWritter;
            if (!oldMap.containsKey(key)) {
                fileWritter = new FileWriter(file.getPath(), true);
                content = addKey;
            } else {
                String oldValue = key + "=" + oldMap.get(key);
                String oldContent = Files.toString(file, Charset.forName("UTF-8"));
                content = StringUtils.replace(oldContent, oldValue, newValue);
                fileWritter = new FileWriter(file.getPath(), false);
            }
            BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
            bufferWritter.write(content);
            bufferWritter.close();
            fileWritter.close();
/*          FileOutputStream out= new FileOutputStream(filepath, true);
            PrintStream ps = new PrintStream(out);
            ps.append(addKey);
            ps.flush();
            ps.close();*/
        } catch (Exception e) {
            AegisLog.error(e);
        }
    }

    public static Map<String, String> loadConfig(String filepath) {
        try {
            File file = loadConfigToFile(filepath);
            if (!file.exists()) {
                throw new FileNotFoundException("file not found");
            }
            //AegisLog.info("load 载入本地配置文件..."+ file.getName());
            Map<String, String> map = FileTransToMap(file);
            return map;
        } catch (Exception e) {
            AegisLog.error(e);
        }
        return null;
    }

    public static File loadConfigToFile(String filepath) {
        try {
            String path = Thread.currentThread().getContextClassLoader().getResource(filepath).getPath();
            File file = new File(path);
            InputStream in = new BufferedInputStream(new FileInputStream(path));
            boolean isUTF = FileCharsetCheck.canDecode(in, Charset.forName("UTF-8"));
            in.close();
            if (!isUTF) {
                FileEncodeConvert.convert(file, "GBK", "UTF-8");
            }
            if (!file.exists()) {
                return null;
            }
            if (!file.canRead()) {
                AegisLog.info("无法读取配置文件." + file.getName());
            }
            return file;

        } catch (Exception e) {
            AegisLog.error(e);
        }
        return null;
    }

    public static Map<String, String> FileTransToMap(File file) {
        try {
            String content = Files.toString(file, Charset.forName("UTF-8"));
            Map<String, String> map = parseMap(content);
            return map;
        } catch (Exception e) {
            AegisLog.error(e);
        }
        return null;
    }

    public static void touchFileIfNotExsit(String filePath, String fileName) {
        if (fileName.isEmpty()) {
            return;
        } else {
            File fInTestResources = new File(filePath);
            if (!fInTestResources.exists()) {
                try {
                    AegisLog.log(fInTestResources.getName() + "不存在，创建空文件");
                    fInTestResources.createNewFile();
                } catch (IOException e) {
                    AegisLog.error(e);
                }
            } else {
                AegisLog.log(fInTestResources.getName() + "已存在");
            }
        }
    }

    public static Boolean replaceFiles(File newFile, File oldFile) {
        Boolean result = false;
        try {
            String newContent = Files.toString(newFile, Charset.forName("UTF-8"));
            FileWriter fileWritter;
            fileWritter = new FileWriter(oldFile.getPath(), false);
            BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
            bufferWritter.write(newContent);
            bufferWritter.close();
            fileWritter.close();
            result = true;
        } catch (Exception e) {
            AegisLog.error(e);
        }
        return result;
    }

    public static Map<String, String> parseMap(String data) throws IOException {
        if (data == null)
            return Collections.emptyMap();
        for (int i = 0; i < data.length(); i++) {
            char c = data.charAt(i);
            if (!Character.isSpaceChar(c)) {
                if (c == '<') {
                    return parseXML(data);
                } else {
                    return parseProperties(data);
                }
            }
        }
        return Collections.emptyMap();
    }

    public static Map<String, String> parseProperties(String data) throws IOException {
        if (data == null) {
            return Collections.emptyMap();
        }
        Properties p = new Properties();
        p.load(new StringReader(data));
        Map<String, String> map = new LinkedHashMap<String, String>(p.size());
        for (String key : p.stringPropertyNames()) {
            map.put(key, p.getProperty(key));
        }
        return map;
    }


    public static Map<String, String> parseXML(String data) throws IOException {
        if (data == null)
            return Collections.emptyMap();

        try {
            Reader reader = new StringReader(data);
            Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(reader));
            XPathFactory factory = XPathFactory.newInstance();
            NodeList nodes = (NodeList) factory.newXPath().compile("/properties/property")
                    .evaluate(doc, XPathConstants.NODESET);

            Map<String, String> map = new LinkedHashMap<String, String>();

            for (int i = 0; i < nodes.getLength(); i++) {
                Element el = (Element) nodes.item(i);
                String name = el.getAttribute("name");
                String value = getString(el.getAttribute("value"), el.getTextContent());
                map.put(name, value);
            }
            return map;
        } catch (Exception e) {
            throw new IOException(e);
        }

    }

    private static String getString(Object o, Object... args) {
        String str = o == null ? null : o.toString();
        if (args == null || args.length == 0 || (str != null && !str.isEmpty()))
            return str;
        for (int i = 0; i < args.length; i++) {
            str = args[i] == null ? null : args[i].toString();
            if (str != null && !str.isEmpty())
                return str;
        }
        return str;
    }
}
